home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
-
- mac_files.c: Copyright (c) Kevin Hammond 1993. All rights reserved.
-
- This module contains Mac file-related code.
-
- These routines are preferred over standard C routines because:
-
- 1) They give better error diagnostics
- 2) They're faster
- 3) They give better control over the Mac file system
- 4) Aliases etc. can be handled properly
-
- HFS support originally by Humayan Lari, UNC.
-
- *****************************************************************************/
-
-
- #pragma segment Files
-
- #include "mac.h"
- #include <fcntl.h>
- #include <Files.h>
- #include <Errors.h>
- #include <Folders.h>
-
- OSErr hopen();
-
- extern CursHandle watchcurs; /* The watch cursor */
- extern short systemVersion; /* Which system we're running under */
- extern char *safemalloc();
-
- /*************************************************
-
- Local definitions.
-
- *************************************************/
-
- /* File types, used by SF Dialogs */
-
- char texttypelist[] = GoferTextTypes;
- char projtypelist[] = GoferProjectTypes;
-
- OSType creator = GoferCreatorType;
- OSType texttype = GoferTextType;
- OSType projtype = GoferProjectType;
- OSType preftype = GoferPrefsType;
-
- /* Dialog handlers */
-
- char *getfile(), *askgetfile(), *putfile(), *opendialog(),
- *savedialog(), *deletedialog();
-
- Boolean revertdialog(), oktosavedialog();
- int shouldsavedialog();
-
-
- SFReply Reply; /* Replies from SF dialogs */
- FSSpec ReplySpec; /* The SF reply record in FSSpec form */
- Boolean ReplyExists; /* Does the reply exist? (Valid only after a putfile call) */
- OSErr ioResult = noErr; /* Result code of last file handling function */
- OSErr err; /* Error codes from OS functions */
-
- Boolean fileIsLocked(); /* Is the file locked? */
- Boolean isVolLocked(); /* Is the volume locked? */
- Boolean isUserLocked(); /* Has the user locked the file? */
-
- /*
- Check for error and notify user if necessary.
- */
-
- Boolean CheckError(char *file, short action, OSErr result)
- {
- if (result != noErr)
- {
- char actionstr[256],
- errorstr[256],
- resultstr[256];
- short errorIndex;
-
- /* Do *not* overwrite original error code, if any */
- if (ioResult == noErr)
- ioResult = result;
-
- /* Get action and result code strings */
- getindstring(actionstr, Res_Action_Strings, action);
- numtostring((long)result,resultstr);
-
- /* Get error explanation */
- switch (result)
- {
- case fLckdErr:
- case permErr:
- errorIndex = StringFileLocked;
- break;
- case vLckdErr:
- case wPrErr:
- errorIndex = StringDiskLocked;
- break;
- case fBsyErr:
- case opWrErr:
- errorIndex = StringFileBusy;
- break;
- case ioErr:
- errorIndex = StringFileError;
- break;
- case noMacDskErr:
- errorIndex = StringDiskError;
- break;
- case fnfErr:
- errorIndex = StringFileNotFound;
- break;
- case wrPermErr:
- errorIndex = StringPermError;
- break;
- default:
- errorIndex = StringUnknownError;
- break;
- }
- getindstring(errorstr, Res_File_Error_Strings, errorIndex);
-
- /* Notify user */
- paramtext(file,actionstr,errorstr,resultstr);
- SetCursor(&qd.arrow);
- (void) Alert(Res_File_Error_Alert, NIL);
-
- return(TRUE);
- }
- else
- return(FALSE);
- }
-
-
-
- /*
- Used by LookForFileInProject to search for a file
- */
-
- static CInfoPBRec gSearchPB;
- static Boolean gEndSearch;
- static char *gSearchfile;
- static short gSearchvolnum;
- static long gSearchdirID;
- static FSSpec fsspec;
-
- void HandleFileSearch(long theDirID)
- /* Recursively search all directories for a file with the given name */
- {
- register short index = 1; /* for ioFDirIndex */
-
- do {
- /* Prepare to call PBGetCatInfo for the current item */
- gSearchPB.dirInfo.ioFDirIndex = index;
- gSearchPB.dirInfo.ioDrDirID = theDirID;
-
- /* Request info about the current item */
- /* And return to the previous level if there's no such item */
- if (PBGetCatInfo(&gSearchPB,false) != noErr)
- return;
-
- if (gSearchPB.dirInfo.ioFlAttrib & ioDirMask)
- /* If we get a folder, we need to recurse */
- HandleFileSearch(gSearchPB.dirInfo.ioDrDirID);
- else
- /* If we get a file, stop the search if it's the one we want */
- {
- if (equalfiles(gSearchfile,p2cstr((char *)gSearchPB.hFileInfo.ioNamePtr)))
- {
- gEndSearch = true;
- gSearchvolnum = gSearchPB.hFileInfo.ioVRefNum;
- gSearchdirID = gSearchPB.hFileInfo.ioFlParID;
-
- resolvealias(&gSearchfile,&gSearchvolnum,&gSearchdirID,TRUE);
- }
- }
-
- /* Increment index for PBGetCatInfo */
- index ++;
- } while (!gEndSearch);
- }
-
- Boolean DoFileSearch(char **file,short *volnum,long *dirID)
- /* Tries to locate the given file by searching a folder and all its subfolders for a file with the given name */
- {
- Str255 nameBuffer;
-
- /* Set up the unchanging fields of the PBGetCatInfo parameter block */
- gSearchPB.dirInfo.ioCompletion = NULL;
- gSearchPB.dirInfo.ioNamePtr = nameBuffer;
- gSearchPB.dirInfo.ioVRefNum = *volnum;
-
- /* Do the search */
- gEndSearch = false;
- gSearchfile = *file;
- gSearchvolnum = 0;
- gSearchdirID = 0;
- HandleFileSearch(*dirID);
-
- /* Let our caller know how things went */
- if (gSearchvolnum != 0 && gSearchdirID != 0)
- {
- *volnum = gSearchvolnum;
- *dirID = gSearchdirID;
- *file = gSearchfile;
- return(TRUE);
- }
- else
- return(FALSE);
- }
-
- /*
- Look for a file belonging to a project, and complain if it can't be located within the given folder.
- */
-
- Boolean LookForFileInProject(char **file,short *volnum,long *dirID)
- {
- FInfo finfo;
- OSErr result;
- char resultstr[256];
-
- result = hgetfinfo(*file,*volnum,*dirID,&finfo);
- if (result != noErr && !DoFileSearch(file,volnum,dirID))
- {
- numtostring((long)result,resultstr);
- paramtext(*file,resultstr,"","");
- SetCursor(&qd.arrow);
- (void) Alert(Res_CantFindProjectFile_Alert, NIL);
- return(FALSE);
- }
- else
- return(TRUE);
- }
-
-
-
- /* Open the input file */
-
- Open_The_File()
- {
- char *file = opendialog();
- updatewindows();
- doopenfile(file,ReplySpec.vRefNum,ReplySpec.parID);
- }
-
-
- /*
- Open the named file.
- */
-
-
- int doopenfile(f,volnum,dirID)
- char *f;
- short volnum;
- long dirID;
- {
- int windex;
-
- resolvealias(&f,&volnum,&dirID,FALSE);
-
- ioResult = noErr;
-
- if(*f!='\0')
- if((windex = findMyWindowName(f,volnum,dirID,FALSE)) != ILLEGAL_WINDOW)
- {
- openthewindow(windex);
- return(windex);
- }
- else
- {
- windex = CreateNewWindow(Res_OpenWindow,f,FALSE,TRUE,AUTO_POSITION,FALSE);
- VREFNUM(windex) = volnum;
- DIRID(windex) = dirID;
- return(readtext(WINDOW(windex),f,TRUE,TRUE));
- }
- else
- return(ILLEGAL_WINDOW);
- }
-
-
- /*
- Open a window, but don't display it, as when printing from
- an Apple event.
- */
-
- doopenforprint(f,volnum,dirID)
- char *f;
- short volnum;
- long dirID;
- {
- int windex = CreateNewWindow(Res_OpenWindow,f,FALSE,FALSE,FALSE,FALSE);
- VREFNUM(windex) = volnum;
- DIRID(windex) = dirID;
- if(readtext(WINDOW(windex),f,TRUE,FALSE))
- return(windex);
- else
- return(ILLEGAL_WINDOW);
- }
-
- /*
- Revert a file from a saved copy.
- Revert even if apparently unchanged -- this file may be shared!
- */
-
- revert(windex)
- int windex;
- {
- ioResult = noErr;
-
- if(revertdialog(FILENAME(windex)))
- {
- updatewindows();
- TESetSelect(0,32767,TEHANDLE(windex));
- TEDelete(TEHANDLE(windex));
- (void) readtext(WINDOW(windex),FILENAME(windex),FALSE,TRUE);
- }
- }
-
-
- /* Delete a file */
-
- dodelete()
- {
- char *file = deletedialog();
- ioResult = noErr;
-
- if(*file != '\0')
- (void) CheckError(file, ActionDelete,
- hdelete(file,ReplySpec.vRefNum,ReplySpec.parID));
- }
-
-
-
- /*
- Read text from a file into a window.
- */
-
-
- int readtext(window,file,closeOnFail,showWin)
- WindowPtr window;
- char *file;
- Boolean closeOnFail, showWin;
- {
- int windex = findMyWindow(window);
-
- if(!isLegalWindow(windex))
- return(ILLEGAL_WINDOW);
-
- if(!doread(file,VREFNUM(windex),DIRID(windex),windex) && closeOnFail)
- {
- CloseAWindow(windex);
- return(ILLEGAL_WINDOW);
- }
- else
- {
- /* Do this even for partially read files */
- AdjustScrollBars(windex);
- ScrollToSelection(windex);
- InvalRect(&(*TEHANDLE(windex))->viewRect);
-
- FLAGS(windex) &= ~WLOCKED;
- if(fileIsLocked(FILENAME(windex),VREFNUM(windex),DIRID(windex),FALSE))
- if (isUserLocked(FILENAME(windex),VREFNUM(windex),DIRID(windex)))
- FLAGS(windex) |= WFLOCKED;
- else
- FLAGS(windex) |= WVLOCKED;
-
- if(showWin)
- {
- DrawControls(WINDOW(windex));
- DrawGrowIcon(WINDOW(windex));
- DrawGoferIcons(windex);
- ShowWindow(WINDOW(windex));
- }
-
- saved(windex);
- MODTIME(windex) = getmodtime(FILENAME(windex),VREFNUM(windex),DIRID(windex));
- return(windex);
- }
- }
-
- Handle ConvertTabs(teh,length,path)
- Handle teh;
- long length;
- short path;
- {
- int i, j, oj;
- int tabs=0, nl=0;
- Handle nteh = NIL;
- char ch;
-
- for(i=0;i < length; ++i)
- if((char) *(*teh+i) == '\t')
- ++tabs;
-
- if(tabs > 0)
- {
- nteh=NewHandle(length+tabs*8);
- if(nteh==NIL)
- {
- if(path >= 0)
- (void)FSClose(path);
- AbortError("Memory ","Not enough memory to convert tabs in file");
- }
-
- for(i=j=0;i<length;++i)
- if((ch = (char) *(*teh+i)) == '\t')
- for(oj=j;j < (oj + 8 - (oj - nl)%8);++j)
- *(*nteh+j) = ' ';
-
- else if(ch == '\r' || ch == '\n')
- {
- *(*nteh+j++) = '\n';
- nl = j;
- }
-
- else
- *(*nteh+j++) = *(*teh+i);
-
- SetHandleSize(nteh,j);
- DisposeHandle(teh);
- return(nteh);
- }
- else
- return(teh);
- }
-
-
- /*
- Read a file into a window.
- */
-
- /* Was there an error? */
- #define CHECK_READ_ERROR(theResult) CheckError(file, ActionOpen, theResult)
-
- /* Uses CHECK_READ_ERROR to check for an error, and then closes the file and leaves the routine if necessary */
- #define HANDLE_READ_ERROR(theResult) if (CHECK_READ_ERROR(theResult)) { if (path != 0) (void) FSClose(path); return(FALSE); }
-
- doread(file,volnum,dirID,windex)
- char *file;
- short volnum;
- long dirID;
- int windex;
- {
- short path = 0;
- long length;
- Handle textHandle;
- long nread;
- OSErr readResult;
-
- /* Open the file */
- SetCursor(*watchcurs);
- HANDLE_READ_ERROR( hopen(file,volnum,dirID,fsRdPerm,&path) );
-
- /* Get its length, and complain if it's too big */
- HANDLE_READ_ERROR( GetEOF(path,&length) );
- if(length > TE_REC_SIZE)
- {
- Complain(file,StringFileTooLarge);
- (void) FSClose(path);
- return(FALSE);
- }
-
- if(MaxBlock() < length + 1024)
- {
- Error("Memory ","Not enough memory left to open file");
- (void) FSClose(path);
- return(FALSE);
- }
-
-
- /* Allocate a handle so we can read in the text */
- textHandle = NewHandle(length);
- if (textHandle == NIL)
- HANDLE_READ_ERROR( MemError() );
-
- /* This seems much less reliable than the code below. It doesn't
- check for partial blocks read, it uses much more memory
- (up to 32K rather than 1K maximum), and doesn't retry network
- reads. It also definitely won't work when BigTextEdit is plugged in. KH
- */
- /* Read the text */
- nread = length;
- HLockHi(textHandle);
- readResult = FSRead(path,&nread,(Ptr)(*textHandle));
- HUnlock(textHandle);
-
- /* If something went wrong, dispose of our handle before notifying the user */
- if (readResult != noErr)
- {
- DisposeHandle(textHandle);
- HANDLE_READ_ERROR(readResult);
- }
-
- textHandle = ConvertTabs(textHandle,length,path);
-
- /* Now plug the handle into the window's TE record and ask TE to recalculate line breaks */
- DisposeHandle((**TEHANDLE(windex)).hText);
- (**TEHANDLE(windex)).hText = textHandle;
- TECalText(TEHANDLE(windex));
-
- /* We're done! */
- HANDLE_READ_ERROR( FSClose(path) );
- path = 0;
-
- GetGoferFileInfo(windex);
-
- return(TRUE);
- }
-
-
-
- /*
- Read a project file.
- */
-
- /* Was there an error? */
- #define CHECK_READPROJ_ERROR(theResult) CheckError(file, ActionOpenProj, theResult)
-
- /* Cleans up after an error by closing the project file and clearing the project */
- #define CLEANUP_READPROJ { if (path != 0) (void) FSClose(path); clearProject(); return (FALSE); }
-
- /* Uses CHECK_READPROJ_ERROR to check for an error, and then cleans up and leaves the routine if necessary */
- #define HANDLE_READPROJ_ERROR(theResult) if (CHECK_READPROJ_ERROR(theResult)) CLEANUP_READPROJ;
-
- Boolean doreadproject(file,volnum,dirID)
- char *file;
- short volnum;
- long dirID;
- {
- extern short projvol;
- extern long projdirID;
-
- short path = 0;
- long length;
- char buff[256], *pbuff = buff;
- long nread;
-
- short filevolnum;
- long filedirID;
- int preservemodtime = TRUE;
-
- extern char projfile[];
-
- /* Check the project filename */
- ioResult = noErr;
- if(*file=='\0')
- return(FALSE);
-
- /* Open the project file */
- SetCursor(*watchcurs);
- ioResult = noErr;
- if (CHECK_READPROJ_ERROR( hopen(file,volnum,dirID,fsRdPerm,&path) ))
- return(FALSE);
-
- /* Find out how long it is */
- if (CHECK_READPROJ_ERROR( GetEOF(path,&length) ))
- {
- (void) CHECK_READPROJ_ERROR( FSClose(path) );
- return(FALSE);
- }
-
- /* Clear project */
- clearProject();
-
- /* Loop through the project file, reading filenames */
- while(length > 0)
- {
- /* Read the length of the filename */
- nread = 1;
- HANDLE_READPROJ_ERROR( FSRead(path,&nread,(Ptr) &buff) );
- nread = (long) buff[0];
-
- /* Read the filename itself */
- HANDLE_READPROJ_ERROR( FSRead(path,&nread,(Ptr) &buff) );
- buff[nread] = '\0';
-
- /* Locate the file */
- filevolnum = volnum;
- filedirID = dirID;
- if (!LookForFileInProject(&pbuff,&filevolnum,&filedirID))
- CLEANUP_READPROJ;
-
- /* Add the file to the project */
- preservemodtime &= AddPItem(pbuff,filevolnum,filedirID,preservemodtime);
- length -= nread+1;
- if(pbuff != buff)
- {
- free(pbuff);
- pbuff = buff;
- }
- }
-
- /* Close the project file */
- HANDLE_READPROJ_ERROR( FSClose(path) );
- path = 0;
-
- /* We're done! */
- strcpy(projfile,file);
- projvol = volnum;
- projdirID = dirID;
- windowtofront(worksheet);
- readScripts(0);
- printPrompt();
- return(TRUE);
- }
-
-
- /*
- Restore Preferences from the named file.
- */
-
- /* Was there an error? */
- #define CHECK_READPREFS_ERROR(theResult) CheckError(file, ActionRestorePrefs, theResult)
-
- /*
- Uses CHECK_READPREFS_ERROR to check for an error,
- and then closes the file and leaves the routine if necessary.
- It is NOT an error if the preferences file doesn't exist!
- This is now handled outside dorestoreprefs.
-
- KH
- */
- #define HANDLE_READPREFS_ERROR(theResult) \
- if (CHECK_READPREFS_ERROR(theResult)) { if (path != 0) (void) FSClose(path); return(FALSE); }
-
- Boolean dorestoreprefs(file,volnum,dirID,toggles)
- char *file;
- short volnum;
- long dirID;
- Boolean toggles;
- {
- short path = 0;
- long length;
- Boolean readOK = TRUE;
- char buff[256];
- long nread;
-
- /* Check the prefs filename */
- ioResult = noErr;
- if(*file=='\0')
- return(FALSE);
-
- /* Open our file */
- HANDLE_READPREFS_ERROR( hopen(file,volnum,dirID,fsRdPerm,&path) );
-
- /* Find out how long it is */
- SetCursor(*watchcurs);
- HANDLE_READPREFS_ERROR( GetEOF(path,&length) );
-
- /* Loop through all the preference items */
- while(length > 0)
- {
- /* Read item length */
- nread = 1;
- HANDLE_READPREFS_ERROR( FSRead(path,&nread,(Ptr) &buff) );
- nread = (long) buff[0];
-
- /* Read item */
- HANDLE_READPREFS_ERROR( FSRead(path,&nread,(Ptr) &buff) );
- buff[nread] = '\0';
- restorepref(buff,toggles);
-
- /* Decrement length */
- length -= nread+1;
- }
-
- /* We're done */
- HANDLE_READPREFS_ERROR( FSClose(path) );
- path = 0;
- return(TRUE);
- }
-
-
-
-
- /*
- Write a file.
-
- Modified by HSL (6/15/92 and 7/16/92 US) for HFS and System 7
- */
-
-
- /*
- HANDLE_WRITE_ERROR uses CHECK_WRITE_ERROR to check for an error.
- If an error has occurred, it then closes and deletes the file
- before exiting the routine.
-
- The following variables are shared between handle_write_error(),
- dowrite() and TEWriteFile().
- */
-
- static short wrtemppath = 0, wrtempvolnum = 0; /* Temporary path and volume */
- static char * wrtempfile; /* Temporary file name */
- static long wrtempdirID = 0L; /* Temporary directory ID */
-
-
- /* Check for write errors */
- #define CHECK_WRITE_ERROR(file,theResult) \
- CheckError(file, ActionSave, theResult)
-
- /* Close a path if it's open */
- #define CLOSE_OPEN_PATH(path) \
- if(path != 0) { (void) FSClose(path); path = 0; }
-
- /* Handle the error and return to our caller */
- #define HANDLE_WRITE_ERROR(res) \
- if(!handle_write_error(file,res)) return(FALSE)
-
-
- /*
- Handle an error during writing.
- If the file is open for writing, close it and delete it.
-
- Return an appropriate exit code (TRUE == no error).
- */
-
- Boolean handle_write_error(file,theResult)
- char *file;
- int theResult;
- {
- if (CHECK_WRITE_ERROR(file,theResult))
- {
- CLOSE_OPEN_PATH(wrtemppath);
- (void) hdelete(wrtempfile,wrtempvolnum,wrtempdirID);
- return(FALSE); \
- }
- return(TRUE);
- }
-
-
- /*
- Set a file system spec.
- */
-
- void setfsspec(char *file,short volnum,long dirID,FSSpec *spec)
- {
- spec->vRefNum = volnum;
- spec->parID = dirID;
-
- strcpy((char *)spec->name,file);
- c2pstr((char *)spec->name);
- }
-
-
- /*
- Write a TE character buffer of length "length" to the open file
- whose path is given by "path".
-
- This routine corrects an error in Humayan's code,
- where a buffer might not be unlocked if the write failed.
-
- KH
- */
-
- OSErr TEWriteFile(path,count,teh)
- short path;
- long count;
- TEHandle teh;
- {
- OSErr result;
- CharsHandle chbuff = TEGetText(teh);
- HLockHigh((Handle) chbuff);
-
- result = FSWrite(path,&count,(Ptr)*chbuff);
- HUnlock((Handle) chbuff);
- return(result);
- }
-
-
- /*
- Checks whether a file is locked.
- */
-
-
- Boolean fileIsLocked(file,volnum,dirID,HandleErr)
- char *file;
- short volnum;
- long dirID;
- Boolean HandleErr;
- {
- OSErr result;
- short path = 0;
-
- if(isUserLocked(file,volnum,dirID))
- result = fLckdErr;
- else
- result = hopen(file,volnum,dirID,fsWrPerm,&path);
-
- if ( result == vLckdErr || result == opWrErr || result == fLckdErr ||
- result == wPrErr || result == permErr || result == wrPermErr )
- {
- if(HandleErr)
- CheckError( file, ActionSave, result );
- return(TRUE);
- }
- else
- {
- CLOSE_OPEN_PATH(path);
- return(isVolLocked(volnum,dirID));
- }
- }
-
-
- /*
- Does the specified file exist.
- */
-
-
- Boolean checkFileExists(file,volnum,dirID)
- char *file;
- short volnum;
- long dirID;
- {
- OSErr ioresult;
- short path = 0;
-
- ioresult = hopen(file,volnum,dirID,fsWrPerm,&path);
- CLOSE_OPEN_PATH(path);
-
- return(ioresult != fnfErr);
- }
-
-
- Boolean isVolLocked(volnum,dirID)
- short volnum;
- long dirID;
- {
- char *tempfile = "Gofer Temp ∂∂∂ ƒƒƒ 12345";
- OSErr result = hcreate(tempfile,volnum,dirID,creator,'????');
- hdelete(tempfile,volnum,dirID);
- return( result == vLckdErr || result == opWrErr || result == wPrErr ||
- result == permErr || result == wrPermErr );
-
- }
-
-
- /*
- Write the contents of a window to "file".
- fileExists indicates whether the file exists already.
- */
-
-
- Boolean dowrite(file,type,volnum,dirID,winfo,updatewinfo)
- char *file;
- OSType type;
- short volnum;
- long dirID;
- int winfo;
- Boolean updatewinfo;
- {
- long count;
- char tempfile[256];
- Boolean usingTempItemsFolder = FALSE; /* Whether we're using the Sys7 temporary folder. */
- Boolean fileExists; /* Whether the file exists. */
-
- /* Prepare to save */
- SetCursor(*watchcurs);
-
- /* Set the temporary write path to NULL */
- wrtemppath = 0;
-
- /*
- Check whether we can write the original file.
- This prevents us overwriting locked or shared files.
-
- It's not necessary to keep the file open, since nothing
- can interrupt us while we're writing (this is because
- System-7 is non-preemptive). On the other hand, it should
- be harmless to do so if we choose, and may prevent e.g.
- network problems if the system ever becomes preemptive.
-
- If the file exists, then we write to a temporary file,
- ideally in the Temporary Items folder.
-
- Otherwise we write the file directly.
- */
-
- fileExists = checkFileExists(file,volnum,dirID);
-
- /* Unset the locked flags -- these will be set later */
- if(updatewinfo)
- FLAGS(winfo) &= ~WLOCKED;
-
- if(fileExists)
- {
- unsigned long seconds;
-
- /*
- Make up a name for our temporary file.
- We need to use strcpy() here!! KH
- */
-
- strcpy(tempfile,GOFER_TEMP);
- wrtempfile = tempfile;
-
- GetDateTime(&seconds);
- numtostring((long)seconds,tempfile+sizeof(GOFER_TEMP)-1);
-
- /* Under System 7, try to put it in the temporary items folder */
- usingTempItemsFolder =
- systemVersion >= 0x0700 &&
- FindFolder(volnum,kTemporaryFolderType,
- kCreateFolder,&wrtempvolnum,&wrtempdirID) == noErr;
-
- /* Check the lock status */
- if(fileIsLocked(file,volnum,dirID,TRUE) )
- {
- if(updatewinfo)
- if(isUserLocked(file,volnum,dirID) )
- FLAGS(winfo) |= WFLOCKED;
- else
- FLAGS(winfo) |= WVLOCKED;
- return( FALSE );
- }
-
- }
- else
- wrtempfile = file;
-
- /*
- If we can't use the special folder, or we're writing the file itself,
- then we use the real file's directory
- */
-
- if (!usingTempItemsFolder)
- {
- wrtempvolnum = volnum;
- wrtempdirID = dirID;
- }
-
- /* Create our temporary or new file */
- HANDLE_WRITE_ERROR( hcreate(wrtempfile,wrtempvolnum,wrtempdirID,creator,type) );
-
- /* Open it (NB: wrtemppath should be 0 here) */
- HANDLE_WRITE_ERROR( hopen(wrtempfile,wrtempvolnum,wrtempdirID,fsWrPerm,&wrtemppath) );
-
- /* Allocate space for the text */
- count = (*TEHANDLE(winfo))->teLength;
- HANDLE_WRITE_ERROR( SetEOF(wrtemppath,count) );
-
- /* Write it */
- HANDLE_WRITE_ERROR( TEWriteFile(wrtemppath,count,TEHANDLE(winfo)) );
-
- /* Close it */
- HANDLE_WRITE_ERROR( FSClose(wrtemppath) );
- wrtemppath = 0;
-
- /* Flush volume info */
- HANDLE_WRITE_ERROR( FlushVol(NIL,wrtempvolnum) );
- HANDLE_WRITE_ERROR( FlushVol(NIL,volnum) );
-
- /* If the file already existed, then we used a temporary file */
- if(fileExists)
- {
- /* If possible, use Sys7 FSpExchangeFiles to swap the two files */
- if(systemVersion >= 0x0700)
- {
- FSSpec tempspec, origspec;
-
- setfsspec(tempfile,wrtempvolnum,wrtempdirID,&tempspec);
- setfsspec(file,volnum,dirID,&origspec);
-
- HANDLE_WRITE_ERROR( FSpExchangeFiles(&tempspec,&origspec) );
- HANDLE_WRITE_ERROR( FSpDelete(&tempspec) );
- }
-
- /*
- If we can't swap the files, delete the original and rename the
- temporary file. Note the assumption that the temporary file was
- created in the same directory as the original file.
- */
- else
- {
- HANDLE_WRITE_ERROR( hdelete(file,volnum,dirID) );
- HANDLE_WRITE_ERROR( hrename(wrtempfile,wrtempvolnum,wrtempdirID,file) );
- }
- }
-
- /* We're done! */
- if(updatewinfo)
- {
- saved(winfo);
- VREFNUM(winfo) = volnum;
- DIRID(winfo) = dirID;
-
- /* Set the file info */
- SetGoferFileInfo(file,winfo);
-
- MODTIME(winfo) = getmodtime(file,volnum,dirID);
-
- /* Redraw the locked icon, in case it's changed */
- DrawLockedIcon(winfo);
- }
-
- return(TRUE);
- }
-
-
-
- /*
- Save a file.
- */
-
- Boolean dosave(winfo,type,dodialog,checksave,setname)
- int winfo;
- Boolean dodialog,checksave,setname;
- OSType type;
- {
- char savefile[256], oldfile[256];
- Boolean savedOK = FALSE;
-
- ioResult = noErr;
- if(checksave && SAVED(winfo))
- return(TRUE);
-
- strcpy(oldfile,FILENAME(winfo));
-
- if(dodialog)
- {
- short menuitem = findmenuitem(Menu_Window,3,1024,oldfile);
-
- if (strcmp(strcpy(savefile,savedialog(oldfile)),"") != 0)
- {
- updatewindows();
-
- savedOK = dowrite(savefile,type,
- ReplySpec.vRefNum,ReplySpec.parID,winfo,setname);
-
- if(setname && savedOK)
- {
- Boolean doupdateold = findHighestVersion(oldfile) > 0;
- setitem(Menu_Window,menuitem,savefile);
- setwindowtitle(winfo,savefile);
- if(doupdateold)
- resetversions(oldfile,winfo);
- }
- }
- }
- else
- {
- if(MODTIME(winfo) == getmodtime(oldfile,VREFNUM(winfo),DIRID(winfo)) ||
- oktosavedialog(oldfile))
- {
- updatewindows();
- savedOK = dowrite(oldfile,type,VREFNUM(winfo),DIRID(winfo),winfo,setname);
- }
- }
-
- return(savedOK);
- }
-
-
- /*
- Simple save, no dialog unless an untitled window.
- The worksheet cannot be saved this way.
- */
-
-
- save(winfo)
- int winfo;
- {
- dosave(winfo,texttype,VIRGIN(winfo),TRUE,TRUE);
- }
-
-
-
- /*
- Save as dialog.
- */
-
- Boolean saveas(winfo)
- int winfo;
- {
- return(dosave(winfo,texttype,TRUE,FALSE,TRUE));
- }
-
-
- /*
- Save a Copy: like "Save as" except the name is not changed
- within MacGofer.
- */
-
-
- saveacopy(winfo)
- int winfo;
- {
- dosave(winfo,texttype,TRUE,FALSE,FALSE);
- }
-
-
- /*
- Set the file info.
- */
-
- setfiletype(file,volume,dirID,creator,type)
- Str255 file;
- short volume;
- long dirID;
- char creator[];
- char type[];
- {
- FInfo finderinfo;
-
- hgetfinfo(file,volume,dirID,&finderinfo);
- finderinfo.fdType = (OSType) type;
- finderinfo.fdCreator = (OSType) creator;
- hsetfinfo(file,volume,dirID,&finderinfo);
- }
-
-
- /*
- Create a new file of the specified type.
- */
-
- createfile(file,volnum,dirID,type)
- char *file;
- short volnum;
- long dirID;
- OSType type;
- {
- OSErr result = hcreate(file,volnum,dirID,creator,type);
-
- /* If unsuccessful report the error using CheckError() */
- if( result != noErr && result != dupFNErr)
- CheckError(file, ActionCreate, result);
- else
- setfiletype(file,volnum,dirID,creator,type);
- }
-
-
-
- /*
- Miscellaneous dialog handlers connected with file I/O.
- */
-
-
- char *savedialog(defaultsave)
- char *defaultsave;
- {
- return(putfile("Save Gofer Source as:",defaultsave,"Save"));
- }
-
-
- char *opendialog()
- {
- return(getfile(1,texttypelist,"Open Gofer File","Open"));
- }
-
-
- char *deletedialog()
- {
- return(askgetfile(-1,texttypelist,"Delete File","Delete",0,Res_Dlg_SFP_Delete));
- }
-
-
- Boolean revertdialog(f)
- char *f;
- {
- return(yesnodialog(Res_Dlg_Revert,f,"",CANCEL)==OK);
- }
-
-
- Boolean oktosavedialog(f)
- char *f;
- {
- return(yesnodialog(Res_Dlg_OkToSave,f,"",CANCEL)==OK);
- }
-
- int shouldsavedialog(w,s)
- int w;
- char *s;
- {
- return(yesnodialog(Res_Dlg_Save,FILENAME(w),s,OK));
- }
-
-
-
- /*
- Save and Restore Information about a Gofer Text file.
- Gofer understands standard EFNT 1003 and MPSR 1005
- resources used by other editors as well as its own
- format.
- */
-
-
- #define FILEINFOVERSION 2
-
-
- /* MacGofer's own file information */
- typedef struct
- {
- short infoversion;
- short literate, hasknum;
- short fontsize, fontnum;
- long selStart, selEnd;
- Rect portRect, iconportRect;
- }
- GoferFileInfo;
-
-
- /* Structure of an MPW File Info record -- MPSR 1005 */
-
- typedef struct
- {
- short fontsize;
- char fontname[32];
- short filler_6;
- short tabs;
- Rect shrunk, grown;
- short filler_a89a;
- short style;
- long selStart, selEnd;
- int filler_0;
- short indent_showinvis;
- }
- MPWFileInfo;
-
-
- /* Structure of a Font Info record -- EFNT 1003 */
- typedef struct
- {
- short fontSize;
- Str255 fontName;
- } FileFontInfo;
-
-
- /*
- Save information for a file.
- */
-
- SetGoferFileInfo(file,winfo)
- char *file;
- int winfo;
- {
- OSErr err;
- GoferFileInfo *finfop;
- short path = HOpenResFile(VREFNUM(winfo),DIRID(winfo),c2pstr(file),fsWrPerm);
- Handle HFinfo = NewHandle(sizeof(GoferFileInfo));
- FileFontInfo *efinfop;
- Handle HEFinfo = NewHandle(sizeof(FileFontInfo));
- MPWFileInfo *mfinfop;
- Handle HMPWFinfo = NIL;
- Point origin;
- GrafPtr SavePort;
-
- if(path < 0)
- {
- HCreateResFile(VREFNUM(winfo),DIRID(winfo),file);
- path = HOpenResFile(VREFNUM(winfo),DIRID(winfo),file,fsWrPerm);
- }
-
- p2cstr(file);
-
- if(path < 0)
- return;
-
- /* Read MPW info if available */
- HMPWFinfo = GetResource(MPWFileInfoType,Res_MPWFileInfo);
-
- /* If no MPW info, set up a default set */
- if(HMPWFinfo == NIL)
- {
- HMPWFinfo = NewHandle(sizeof(MPWFileInfo));
- HLock(HMPWFinfo);
- mfinfop = (MPWFileInfo *) *HMPWFinfo;
- mfinfop->filler_6 = 6;
- mfinfop->filler_0 = 0;
- mfinfop->filler_a89a = 0xa89a;
- mfinfop->tabs = 8;
- mfinfop->style = 0xca74; /* Plain */
- mfinfop->indent_showinvis = 0x100; /* Auto-Indent, Don't show invis */
- mfinfop->fontsize = 9; strcpy(mfinfop->fontname,"monaco");
- mfinfop->selStart = mfinfop->selEnd = 0;
- }
- else
- {
- HLock(HMPWFinfo);
- mfinfop = (MPWFileInfo *) *HMPWFinfo;
- }
-
- HLock(HFinfo);
- finfop = (GoferFileInfo *) *HFinfo;
-
- finfop->infoversion = FILEINFOVERSION;
- finfop->literate = (FLAGS(winfo) & WLITERATE)?1:0;
- finfop->hasknum = (FLAGS(winfo) & WHNUM)?1:0;
- finfop->portRect = WINDOW(winfo)->portRect;
-
- GetPort(&SavePort);
- SetPort(WINDOW(winfo));
- SetPt(&origin,0,0);
- LocalToGlobal(&origin);
- OffsetRect(&finfop->portRect,origin.h,origin.v);
- mfinfop->shrunk = mfinfop->grown = finfop->portRect;
-
- if(ICONWINDOW(winfo)!=NIL)
- {
- finfop->iconportRect = ICONWINDOW(winfo)->portRect;
-
- SetPort(ICONWINDOW(winfo));
- SetPt(&origin,0,0);
- LocalToGlobal(&origin);
- OffsetRect(&finfop->iconportRect,origin.h,origin.v);
- }
-
- SetPort(SavePort);
-
- if(isEditWindow(winfo))
- {
- TEHandle teh = TEHANDLE(winfo);
- HLock(HEFinfo);
- efinfop = (FileFontInfo *) *HEFinfo;
-
- mfinfop->fontsize = finfop->fontsize = efinfop->fontSize = (*teh)->txSize;
- finfop->fontnum = (*teh)->txFont;
- mfinfop->selStart = finfop->selStart = (long) (*teh)->selStart;
- mfinfop->selEnd = finfop->selEnd = (long) (*teh)->selEnd;
-
- GetFontName(finfop->fontnum,&(efinfop->fontName));
- getfontname(finfop->fontnum,mfinfop->fontname);
- HUnlock(HEFinfo);
-
- SetHandleSize(HEFinfo,sizeof(short)+1+*((char *)(efinfop->fontName)));
-
- /* Create EFNT 1003 */
- addresource(HEFinfo,FontInfoType,Res_FontInfo,"Font Size & Name");
- err=ResError();
- }
- else
- {
- finfop->fontsize = finfop->fontnum = 0;
- finfop->selStart = finfop->selEnd = 0;
- }
-
- HUnlock(HFinfo);
- addresource(HFinfo,GoferFileInfoType,Res_GoferFileInfo,"Gofer Information");
- err=ResError();
-
- HUnlock(HMPWFinfo);
- addresource(HMPWFinfo,MPWFileInfoType,Res_MPWFileInfo,"MPW Window Info");
- err=ResError();
-
- CloseResFile(path);
-
- DetachResource(HFinfo);
- DisposeHandle(HFinfo);
- DetachResource(HEFinfo);
- DisposeHandle(HEFinfo);
- DetachResource(HMPWFinfo);
- DisposeHandle(HMPWFinfo);
- }
-
-
- /*
- Restore information when reading a file.
- */
-
-
- GetGoferFileInfo(winfo)
- int winfo;
- {
- short path = HOpenResFile(VREFNUM(winfo),DIRID(winfo),c2pstr(FILENAME(winfo)),fsRdPerm);
- Handle gres = NIL, fres = NIL, mres = NIL;
- GoferFileInfo *finfop;
- FileFontInfo *efinfop;
- MPWFileInfo *mfinfop;
-
- p2cstr(FILENAME(winfo));
- if(path < 0)
- return;
-
- /* MPSR 1005 takes priority over EFNT 1003 and Gofer info */
- mres = GetResource(MPWFileInfoType,Res_MPWFileInfo);
-
- /* Restore the font, size and selection range */
- if(mres != NIL && (isEditWindow(winfo) || iconic(winfo)))
- {
- short fontnum;
- HLock(mres);
- mfinfop = (MPWFileInfo *) *mres;
- GetFNum(mfinfop->fontname,&fontnum);
- if(fontnum != 0 && mfinfop->fontsize > 0 && mfinfop->fontsize < 256)
- updateFont(winfo,fontnum,mfinfop->fontsize);
-
- /* Restore the selection range */
- TESetSelect((short)mfinfop->selStart,(short)mfinfop->selEnd,TEHANDLE(winfo));
- }
-
-
- /* EFNT 1003 takes priority over Gofer-specific info */
- if(mres == NIL)
- fres = GetResource(FontInfoType,Res_FontInfo);
-
- /* Restore the font and size */
- if(fres != NIL && (isEditWindow(winfo) || iconic(winfo)))
- {
- short fontnum;
- HLock(fres);
- efinfop = (FileFontInfo *) *fres;
- GetFNum(efinfop->fontName,&fontnum);
- if(fontnum != 0 && efinfop->fontSize > 0 && efinfop->fontSize < 256)
- updateFont(winfo,fontnum,efinfop->fontSize);
- HUnlock(fres);
- DetachResource(fres);
- DisposeHandle(fres);
- }
-
-
- gres = GetResource(GoferFileInfoType,Res_GoferFileInfo);
- if(gres != NIL)
- {
- HLock(gres);
- finfop = (GoferFileInfo *) *gres;
- if(finfop->literate==1)
- FLAGS(winfo) |= WLITERATE;
- else
- FLAGS(winfo) &= ~WLITERATE;
-
- if(finfop->hasknum==1)
- FLAGS(winfo) |= WHNUM;
- else
- FLAGS(winfo) &= ~WHNUM;
-
-
- if(mres == NIL && (isEditWindow(winfo) || iconic(winfo)))
- {
- char thefont[256];
- getfontname(finfop->fontnum,thefont);
-
- /*
- Check whether the saved font exists and is a sensible size,
- and if so, set it for winfo's TE record
- */
-
- if(fres == NIL && *thefont != '\0' && finfop->fontsize > 0 && finfop->fontsize < 256)
- updateFont(winfo,finfop->fontnum,finfop->fontsize);
-
- /* Restore the selection range */
- TESetSelect((short)finfop->selStart,(short)finfop->selEnd,TEHANDLE(winfo));
- }
-
-
- /* Restore the size and position of the window, if possible */
- if(mres != NIL || finfop->infoversion > 0)
- {
- Rect pr = mres == NIL? finfop->portRect:mfinfop->shrunk;
-
- /* Sanity checks for off-screen windows */
- if(pr.left >= qd.screenBits.bounds.right - 10 ||
- pr.left <= qd.screenBits.bounds.left + 10)
- {
- pr.right -= pr.left;
- pr.left = qd.screenBits.bounds.left + 10;
- pr.right += pr.left;
- }
-
- if(pr.right >= qd.screenBits.bounds.right - 10 ||
- pr.right <=qd.screenBits.bounds.left + 10)
- pr.right = qd.screenBits.bounds.right - 10;
-
- if(pr.top >= qd.screenBits.bounds.bottom - 10 ||
- pr.top <= qd.screenBits.bounds.top + 10)
- {
- pr.bottom -= pr.top;
- pr.top = qd.screenBits.bounds.top + 10;
- pr.bottom += pr.top;
- }
-
- if(pr.bottom >= qd.screenBits.bounds.bottom - 10 ||
- pr.bottom <= qd.screenBits.bounds.top + 10)
- pr.bottom = qd.screenBits.bounds.bottom - 10;
-
- MoveWindow(WINDOW(winfo), pr.left, pr.top, false);
- SizeWindow(WINDOW(winfo), pr.right - pr.left, pr.bottom - pr.top, false);
- ResizeTheWindow(WINDOW(winfo));
-
- /* Restore the icon window position if it's been saved */
- if(finfop->infoversion > 1)
- {
- CreateIconWindow(winfo,FALSE);
- pr = finfop->iconportRect;
-
- /* Sanity tests for icons -- 26 is a magic number */
- if(pr.left >= qd.screenBits.bounds.right - 26)
- {
- pr.right -= pr.left;
- pr.left = qd.screenBits.bounds.right - 26;
- pr.right += pr.left;
- }
-
- if(pr.left <= qd.screenBits.bounds.left + 26)
- {
- pr.right -= pr.left;
- pr.left = qd.screenBits.bounds.left + 26;
- pr.right += pr.left;
- }
-
- if(pr.top >= qd.screenBits.bounds.bottom - 26)
- {
- pr.bottom -= pr.top;
- pr.top = qd.screenBits.bounds.bottom - 26;
- pr.bottom += pr.top;
- }
-
- if(pr.top <= qd.screenBits.bounds.top + 26)
- {
- pr.bottom -= pr.top;
- pr.top = qd.screenBits.bounds.top + 26;
- pr.bottom += pr.top;
- }
-
- MoveWindow(ICONWINDOW(winfo), pr.left, pr.top, false);
- }
- }
-
- HUnlock(gres);
- HUnlock(mres);
-
- CloseResFile(path);
- DetachResource(gres);
- DisposeHandle(gres);
- DetachResource(mres);
- DisposeHandle(mres);
- }
- else
- CloseResFile(path);
- }
-
-
- /*
- Determine whether a file is literate by:
-
- 1) Checking the file information;
- 2) Reading the first character.
- */
-
- IsLiterateFile(volnum,dirID,file)
- short volnum;
- long dirID;
- char *file;
- {
- short path;
- Boolean result = FALSE;
-
- resolvealias(&file,&volnum,&dirID,FALSE);
-
- path = HOpenResFile(volnum,dirID,c2pstr(file),fsRdPerm);
-
- p2cstr(file);
- if(path >= 0)
- {
- Handle gres = GetResource(GoferFileInfoType,Res_GoferFileInfo);
-
- if(gres != NIL)
- {
- result = ((GoferFileInfo *) *gres)->literate==1;
- CloseResFile(path);
- DetachResource(gres);
- DisposeHandle(gres);
- }
- else
- CloseResFile(path);
- }
-
- /* Otherwise, check whether the first character is '>' */
- if(!result)
- {
- long length;
- if(hopen(file,volnum,dirID,fsRdPerm,&path) == noErr)
- {
- if( GetEOF(path,&length) == noErr && length > 0)
- {
- char firstch;
- length = 1;
- if(FSRead(path,&length,(Ptr)(&firstch)) == noErr)
- result = firstch == '>';
- }
- (void) FSClose(path);
- }
- }
- return(result?1:0);
- }
-
-
- /*
- Determine whether Haskell Numbers should be used for this file,
- by reading the saved file information.
- */
-
-
- IsHaskNumFile(volnum,dirID,file)
- short volnum;
- long dirID;
- char *file;
- {
- short path;
- Boolean result = FALSE;
-
- resolvealias(&file,&volnum,&dirID,FALSE);
-
- path = HOpenResFile(volnum,dirID,c2pstr(file),fsRdPerm);
-
- p2cstr(file);
- if(path >= 0)
- {
- Handle gres = GetResource(GoferFileInfoType,Res_GoferFileInfo);
-
- if(gres != NIL)
- {
- result = ((GoferFileInfo *) *gres)->hasknum==1;
- CloseResFile(path);
- DetachResource(gres);
- DisposeHandle(gres);
- }
- else
- CloseResFile(path);
- }
- return(result?1:0);
- }
-
-
- /*
- Resolve a System 7 alias
- */
-
-
- static FSSpec fsspec;
- resolvealias(file,volnum,dirID,copyname)
- char **file;
- long *dirID;
- short *volnum;
- Boolean copyname;
- {
- /* Resolve an alias, perhaps */
- if(systemVersion >= 0x0700)
- {
- Boolean wasFolder, wasAliased;
-
- fsmakefsspec(*file,*volnum,*dirID,&fsspec);
- ResolveAliasFile(&fsspec,TRUE,&wasFolder,&wasAliased);
-
- if(wasFolder)
- return;
-
- if(wasAliased)
- {
- /* Copy the resolved alias */
- if(copyname)
- {
- *file = safemalloc((int)(fsspec.name[0])+1);
- pstrcopy(fsspec.name,*file);
- }
- else
- *file = (char *)fsspec.name;
-
- p2cstr(*file);
- *volnum = fsspec.vRefNum;
- *dirID = fsspec.parID;
- }
- }
- }
-